﻿using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using ParamSetCollection.General.Logs;
using ParamSetCollection.General.Parameters.Normal;

namespace ParamSetCollection.General.Parameters.Normal
{
    public delegate void OnBitValueSetCmdEventHandler(int mainAddr, int bitIndex, byte[] baseValue, bool setValue, string idcType);
    public delegate void OnValueSetCmdEventHandler(int addr, byte[] data, string idcType);
    public delegate void OnValueRenewEventHandler(string viewValue);//参数更新通知
    public delegate void OnValueChangeLogHandler(ParamRenewLogMsgUnit logUnit);//参数修改log

    public class ParameterUnit
    {
        #region============================== 变量 ====================================
        //参数值改变
        public event OnBitValueSetCmdEventHandler OnBitValueSet;
        public event OnValueSetCmdEventHandler OnValueSetCmd;
        public event OnValueRenewEventHandler OnValueRenew;
        public event OnValueChangeLogHandler OnValueChangeLog;


        private DataUnit BindingData = null;

        private string m_code = "";//变量名
        private Dictionary<string, string> m_names = new Dictionary<string, string>();//自定义名称，与所选语言绑定
        private string m_mesName = "";//用于mes的名字，默认为英文名

        private bool m_remoteEnable = false;//允许上传,空字符为允许上传
        private bool m_logEnable = true;//允许记录log
        private bool m_plcRenewLogEnable = false;//允许记录从plc更新的不同值

        public string IDCType = "D";//元件类型
        public Type ParamType = typeof(short);//变量类型
        public decimal Times = 1;//倍率,显示的值与跟PLC交互的值非1;1关系
        public decimal m_value = 0;//值
        private string m_unit = "";//单位
        private string m_position = "0";//地址
        private string m_format = "%d";//格式，%0.1f,%d, bit
        private decimal m_max = 1000;//最大值,限制倍率处理前的值
        private decimal m_min = 0;//最小值，限制倍率处理前的值

        public decimal m_fMax = 987654;
        public decimal m_fMin = 987654;

        public int m_iMax = 987654;
        public int m_iMin = 987654;

        public string refValue = "";//参考值，用于配方页面参数更新动作判断
        public string m_oldViewValue = "";
        public string m_viewValue = "0";
        public string HistorySetRequest = "";

        private CommDataUnit m_commDataUnit1 = null;
        private int m_unit1RenewMark = -1;//-1为不作更新判断
        private CommDataUnit m_commDataUnit2 = null;
        private int m_unit2RenewMark = -1;//-1为不作更新判断


        //public List<ParamUnit> UIupdateList = new List<ParamUnit>();
        public List<ParamUnit> ShortUpdateList = new List<ParamUnit>();
        #endregion=====================================================================


        #region============================== 属性 ====================================

        public string Code { get { return m_code; } set { m_code = value; } }
        public Dictionary<string, string> Names { get { return m_names; } set { m_names = value; } }//----字典类型
        public string MesName { get { return m_mesName; } set { m_mesName = value; } }

        public bool RemoteEnable { get { return m_remoteEnable; } set { m_remoteEnable = value; } }

        public bool LogEnable { get { return m_logEnable; } set { m_logEnable = value; } }

        public string Unit { get { return m_unit; } set { m_unit = value; } }
        public string Position { get { return m_position; } set { m_position = value; } }
        public string Format { get { return m_format; } set { m_format = value; } }
        public decimal Max { get { return m_max; } set { m_max = value; } }
        public decimal Min { get { return m_min; } set { m_min = value; } }

        public string ViewValue { get { return m_viewValue; } }

        public string Value
        {
            get { return m_value.ToString(); }
            set { value = value; }
            //set
            //{
            //    if (m_value != value)
            //    {
            //        if (LogEnable)
            //            OnValueChange?.Invoke(new ParamRenewLogMsgUnit(Names, m_viewValue, TransformToViewValue(value), Unit, Format));//变量名以_swt作为开关区分

            //        UpdateParamList(value);
            //        m_value = value;
            //    }
            //    else
            //    {
            //        List<ParamUnit> deleBuf = new List<ParamUnit>();

            //        for (int i = 0; i < ShortUpdateList.Count; i++)
            //        {

            //            if (ShortUpdateList[i].Valid == false)
            //            {
            //                deleBuf.Add(ShortUpdateList[i]);
            //            }
            //        }

            //        for (int i = 0; i < deleBuf.Count; i++)
            //        {
            //            ShortUpdateList.Remove(deleBuf[i]);
            //        }

            //        deleBuf.Clear();
            //    }

            //}
        }

        //public string ViewValue
        //{
        //    get
        //    {
        //        return GetValToViewFormatStr(m_value);
        //    }
        //    set
        //    {

        //        m_value = GetViewToValFormatStr(m_value, value);
        //    }
        //}



        #endregion=====================================================================


        #region============================= 内部函数 ================================




        //更新到临时变量
        private void UpdateParamList(string value)
        {
            List<ParamUnit> deleBuf = new List<ParamUnit>();


            for (int i = 0; i < ShortUpdateList.Count; i++)
            {
                ShortUpdateList[i].Value = value;
                if (ShortUpdateList[i].Valid == false)
                {
                    deleBuf.Add(ShortUpdateList[i]);
                }
            }

            for (int i = 0; i < deleBuf.Count; i++)
            {
                ShortUpdateList.Remove(deleBuf[i]);
            }

            deleBuf.Clear();
        }

        private string TransformToViewValue(string str)
        {
            if (m_format == "%0.1f")
            {
                Single v;
                bool rs = Single.TryParse(str, out v);
                if (rs == true)
                {
                    return ((v / 10)).ToString("0.0");
                }

                return "0.0";
            }
            else if (m_format == "%0.2f")
            {
                Single v;
                bool rs = Single.TryParse(str, out v);
                if (rs == true)
                {
                    return ((v / 100)).ToString("0.00");
                }

                return "0.00";
            }
            else
            {
                return str;
            }
        }

        public string GetValToViewFormatStr(string val)
        {
            if (m_format == "%0.1f")
            {
                decimal v;
                bool rs = decimal.TryParse(val, out v);
                if (rs == true)
                {
                    return ((v / 10)).ToString("0.0");
                }

                return "0.0";
            }
            else if (m_format == "%0.2f")
            {
                decimal v;
                bool rs = decimal.TryParse(val, out v);
                if (rs == true)
                {
                    return ((v / 100)).ToString("0.00");
                }

                return "0.00";
            }
            else
            {
                return val;
            }
        }

        public string GetViewToValFormatStr(string baseVal, string ObjVal)
        {
            if (m_format == "%0.1f")
            {
                Single v;
                bool rs = Single.TryParse(ObjVal, out v);
                if (rs == true)
                {
                    return ((int)(decimal)(v * 10)).ToString();
                }
                else
                {
                    return baseVal;
                }
            }
            else if (m_format == "%0.2f")
            {
                Single v;
                bool rs = Single.TryParse(ObjVal, out v);
                if (rs == true)
                {
                    return ((int)(decimal)(v * 100)).ToString();
                }
                else
                {
                    return baseVal;
                }
            }
            else
            {
                return baseVal;
            }
        }

        private void ReduceRange()
        {
            if (m_format == "%0.1f")
            {

                m_fMax = Convert.ToDecimal(m_max);
                m_fMin = Convert.ToDecimal(m_min);


            }
            else if (m_format == "%0.2f")
            {

                m_fMax = Convert.ToDecimal(m_max);
                m_fMin = Convert.ToDecimal(m_min);




            }
            else if (m_format == "%d")
            {

                m_iMax = Convert.ToInt32(m_max);
                m_iMin = Convert.ToInt32(m_min);



            }

        }

        private void CheckDataRenew()
        {
            if (m_unit1RenewMark == 1 && m_unit2RenewMark == 1)
            {
                //更新双字
                UpdateDW(m_commDataUnit1.Data, m_commDataUnit2.Data);
            }
            else if (m_unit1RenewMark == 1 && m_unit2RenewMark == -1)
            {
                //更新单字
                UpdateWord(m_commDataUnit1.Data);
            }
        }

        private void ComfirmChange(decimal val)
        {

            decimal buff = val * Times;

            if (ParamType == typeof(double))
            {
                double dbuff = (double)buff;
                byte[] byteGroup = BitConverter.GetBytes(dbuff);

                OnValueSetCmd?.Invoke(m_commDataUnit1.Addr, byteGroup, IDCType);
            }
            else if (ParamType == typeof(short))
            {
                short dbuff = (short)buff;
                byte[] byteGroup = BitConverter.GetBytes(dbuff);

                OnValueSetCmd?.Invoke(m_commDataUnit1.Addr, byteGroup, IDCType);
            }
            else if (ParamType == typeof(ushort))
            {
                ushort dbuff = (ushort)buff;
                byte[] byteGroup = BitConverter.GetBytes(dbuff);

                OnValueSetCmd?.Invoke(m_commDataUnit1.Addr, byteGroup, IDCType);
            }

        }

        private void ComfirmChange(bool val)
        {
            ShortBits buff = m_commDataUnit1.Data;
            int subAddr = 0;
            int mainAddr = 0;
            int index = Position.IndexOf(".");
            string mainAddrStr = Position.Substring(0, index);
            string subAddrStr = Position.Substring(index + 1, Position.Length - index);
            int.TryParse(mainAddrStr, out mainAddr);
            int.TryParse(subAddrStr, out subAddr);


            buff[subAddr] = val;

            byte[] byteGroup = BitConverter.GetBytes(m_commDataUnit1.Data);

            OnBitValueSet?.Invoke(mainAddr, subAddr, byteGroup, val, IDCType);

        }
        #endregion====================================================================


        #region============================= 保护函数 ================================
        private void UpdateWord(ushort data)
        {
            if ((decimal)data != m_value)//值变化
            {
                //触发值更新相关动作
                //更新基础值
                m_value = (decimal)data;

                //记录历史显示值
                m_oldViewValue = m_viewValue;

                //更新显示值
                RenewViewValue(data);

                //触发值更新事件


                //触发log事件(需要先设置，是否记录plc读取值更新,即反向更新log)
            }

        }

        private void UpdateDW(ushort data1, ushort data2)
        {
            //ushort转byte
            float data = (float)((data1 << 16) + data2);
            if ((decimal)data != m_value)
            {
                //触发值更新相关动作
                //更新基础值
                m_value = (decimal)data;

                //记录历史显示值
                m_oldViewValue = m_viewValue;

                //更新显示值
                RenewViewValueDW((decimal)data);

                //触发log事件(需要先设置，是否记录plc读取值更新,即反向更新log)

                OnValueRenew?.Invoke(m_viewValue);
            }

        }


        private void RenewViewValue(ushort data)
        {

            if (ParamType == typeof(short))
            {
                decimal v = (short)data;
                m_viewValue = (v / Times).ToString();//从PLC更新值不受格式限制，以防误判

                OnValueRenew?.Invoke(m_viewValue);
            }
            else if (ParamType == typeof(ushort))
            {
                decimal v = (ushort)data;
                m_viewValue = (v / Times).ToString();//从PLC更新值不受格式限制，以防误判

                //触发值更新事件
                OnValueRenew?.Invoke(m_viewValue);
            }


        }

        private void RenewViewValueDW(decimal data)
        {
            //需要追加转化逻辑
            decimal v = 0;
            v = data;
            m_viewValue = (v / Times).ToString();//从PLC更新值不受格式限制，以防误判

            //触发值更新事件
            OnValueRenew?.Invoke(m_viewValue);


        }


        #endregion====================================================================


        #region============================= 公开函数 ================================
        public ParameterUnit(string code)
        {
            m_code = code;
            //m_language = "0";
        }




        public void ReadXml(XmlNode mainNode)
        {
            for (int i = 0; i < mainNode.ChildNodes.Count; i++)
            {
                XmlNode node = mainNode.ChildNodes[i];
                switch (node.Name)
                {

                    case "MesName":
                        MesName = node.InnerText;
                        break;
                    case "RemoteEnable":
                        bool.TryParse(node.InnerText, out m_remoteEnable);

                        break;
                    case "LogEnable":
                        bool.TryParse(node.InnerText, out m_logEnable);
                        break;

                    case "PlcRenewLogEnable":
                        bool.TryParse(node.InnerText, out m_plcRenewLogEnable);
                        break;
                    case "Unit":
                        Unit = node.InnerText;
                        break;

                    case "Format":
                        Format = node.InnerText;
                        break;
                    case "Value":
                        Value = node.InnerText;
                        break;
                    case "Max":
                        decimal.TryParse(node.InnerText, out m_max);
                        break;
                    case "Min":
                        decimal.TryParse(node.InnerText, out m_min);
                        break;
                    default:
                        if (node.Name.Contains("Name"))
                        {
                            if (m_names.ContainsKey(node.Name) == false)
                            {
                                m_names.Add(node.Name, node.InnerText);
                            }

                        }

                        break;
                }
            }

        }

        //-1--格式错误，-2--过小，-3--过大
        public int CheckValue(string v, out decimal dVal)
        {
            string value = Value;
            int rs = -1;

            dVal = 0;
            int index1 = v.IndexOf(".");
            int index2 = Format.IndexOf(".");
            if (index1 == -1)
            {
                if (decimal.TryParse(v, out dVal))
                {
                    if (dVal >= m_min && dVal <= m_max)
                    {
                        rs = 0;
                    }
                    else if (dVal < m_min)
                    {
                        rs = -2;
                    }
                    else if (dVal > m_max)
                    {
                        rs = -3;
                    }
                }
            }
            else if (Format.Contains("%0."))
            {
                string s = Format.Substring(index2 + 1, 1);
                int c = 0;
                if (int.TryParse(s, out c) == true)
                {
                    //对比小数位数
                    if (v.Length - index1 <= c)
                    {
                        if (decimal.TryParse(v, out dVal))
                        {
                            if (dVal >= m_min && dVal <= m_max)
                            {
                                rs = 0;
                            }
                            else if (dVal < m_min)
                            {
                                rs = -2;
                            }
                            else if (dVal > m_max)
                            {
                                rs = -3;
                            }
                        }
                    }
                }
            }

            return rs;
        }

        public bool CheckValue(string v)
        {
            decimal dVal = 0;
            if (decimal.TryParse(v, out dVal) == false)
            {
                return false;
            }


            int index1 = v.IndexOf(".");
            int index2 = Format.IndexOf(".");
            if (index1 == -1)
            {
                if (decimal.TryParse(v, out dVal))
                {
                    if (dVal >= m_min && dVal <= m_max)
                    {
                        return true;
                    }
                    else if (dVal < m_min)
                    {
                        return false;
                    }
                    else if (dVal > m_max)
                    {
                        return false;
                    }
                }
            }
            else if (Format.Contains("%0."))
            {
                string s = Format.Substring(index2 + 1, 1);
                int c = 0;
                if (int.TryParse(s, out c) == true)
                {
                    //对比小数位数
                    if (v.Length - index1 <= c)
                    {
                        if (decimal.TryParse(v, out dVal))
                        {
                            if (dVal >= m_min && dVal <= m_max)
                            {
                                return true;
                            }
                            else if (dVal < m_min)
                            {
                                return false;
                            }
                            else if (dVal > m_max)
                            {
                                return false;
                            }
                        }
                    }
                }
            }

            return false;
        }




        public ParameterUnit ShallowClone()
        {

            ParameterUnit newParam = null;


            return newParam;
        }

        public void SetRefValue()
        {
            refValue = m_viewValue;
        }


        public void InputBindingData(DataUnit du)
        {
            du.OnMainRenewValue += Du_OnMainRenewValue;
            BindingData = du;
        }

        public void InputBindingData(CommDataUnit du1, CommDataUnit du2 = null)
        {
            m_commDataUnit1 = du1;
            m_commDataUnit2 = du2;

            if (m_commDataUnit1 != null)
            {
                m_commDataUnit1.OnRenew += M_commDataUnit1_OnRenew;
                m_unit1RenewMark = 0;
            }

            if (m_commDataUnit2 != null)
            {
                m_commDataUnit2.OnRenew += M_commDataUnit2_OnRenew;
                m_unit2RenewMark = 0;
            }
        }

        public int SetValue(string val)
        {
            decimal buff = 0;
            int rs = CheckValue(val, out buff);
            if (rs == 0)
            {
                OnValueChangeLog?.Invoke(new ParamRenewLogMsgUnit(Names, m_oldViewValue, val, Unit, Format));

                //触发值修改事件，转化命令队列
                ComfirmChange(buff);
            }

            HistorySetRequest = val;
            return rs;
        }

        public void SetValue(bool val)
        {
            OnValueChangeLog?.Invoke(new ParamRenewLogMsgUnit(Names, m_oldViewValue, val.ToString(), Unit, Format));

            ComfirmChange(val);
            HistorySetRequest = val.ToString();
        }

        #endregion====================================================================


        #region============================= 消息响应 ================================
        private void Du_OnMainRenewValue(string baseValue)
        {

        }

        private void M_commDataUnit2_OnRenew()
        {
            m_unit2RenewMark = 1;
            CheckDataRenew();
        }

        private void M_commDataUnit1_OnRenew()
        {
            m_unit1RenewMark = 1;
            CheckDataRenew();
        }
        #endregion====================================================================
    }
}
